/*
 *  Copyright (C) 2013 Harry Wei <harryxiyou@gmail.com>
 *                     Lei Han <bonben@126.com>
 *
 *  This program is free software; you can redistribute it and/or modify it
 *  under the terms of the GNU General Public License version 2 as published by
 *  the Free Software Foundation.
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <glib.h>
#include "ffssim_ctrl.h"
#include "storage.h"
#include "storage_helper.h"
#include "bs_local.h"

/*FIXME: handle logs*/
#define HLOG_DEBUG		printf
#define HLOG_INFO		printf
#define HLOG_ERROR		printf

#if 0
CTRL_REGION_T CTRL_REGION;
extern int append_log(struct hlfs_ctrl *ctrl, const char *db_buff, \
		uint32_t db_start, uint32_t db_end, uint32_t no_compressed);
int flush_log(struct hlfs_ctrl *ctrl, const char *db_buff, \
		uint32_t db_start, uint32_t db_end)
{
	if ((NULL == ctrl) || (NULL == db_buff) || db_end < db_start) {
		HLOG_ERROR("Params Error");
		return -1;
	}
	//HLOG_DEBUG("enter func %s", __func__);
	//HLOG_DEBUG("last segno: %u last offset: %u", ctrl->last_segno, \
	ctrl->last_offset);
	g_mutex_lock (ctrl->hlfs_access_mutex);
	ctrl->last_write_timestamp = get_current_time();
	int size = append_log(ctrl, db_buff, db_start, db_end, 1);
	g_mutex_unlock (ctrl->hlfs_access_mutex);
	if (size < 0) {
		HLOG_ERROR("append log error");
		return -1;
	}
	HLOG_INFO("Append Log Exec Succ . file_size:%llu, last_segno:%u, \
			last_offset:%u, log_size:%u, start_dbno:%u, end_dbno:%u",
			ctrl->inode.length,
			ctrl->last_segno,
			ctrl->last_offset,
			size,
			db_start,
			db_end)
		//HLOG_DEBUG("last offset: %u", ctrl->last_offset);
		return size;
}
#endif
int init_from_superblock(struct back_storage *storage,struct ffssim_ctrl *ctrl)
{
	struct super_block *sb= &ctrl->sb;
        
   	int ret = read_fs_sb_meta(storage,&sb->block_size,&sb->max_fs_size,&sb->chunk_size);
	g_assert(0 == ret);
	ctrl->start_segno=0;
	ctrl->last_segno=1;
	ctrl->last_offset=1;
	g_strlcpy(&sb->fsname,"FFSSIM",MAX_FILE_NAME_LEN);

	return 0;
	
}
#if 0
int init_from_superblock(struct back_storage *storage, 
		                 struct ffssim_ctrl *ctrl)
{
	HLOG_DEBUG("enter func %s", __func__);     
	if ((NULL == storage) || (NULL == ctrl)) {
		HLOG_ERROR("read fs superblock error");
		return -1;
	}
	struct super_block *sb = &ctrl->sb;
	char *father_uri = NULL;
	uint64_t snapshot_inode;
	uint32_t from_segno = 0;
	int ret = read_fs_meta_all(storage, &(sb->seg_size), \
			&(sb->block_size), &(sb->max_fs_size), &(ctrl->is_compress), \
			&father_uri, &snapshot_inode, &from_segno);
	g_assert(ret ==0);
	HLOG_DEBUG("father uri:%s", father_uri);
	if (father_uri != NULL) {
		HLOG_DEBUG("father uri:%s", father_uri);
		FAMILY_CTRL *family = family_new();
		faimly_init(family, father_uri, snapshot_inode, from_segno);
		ctrl->family = family;
	}			
	g_strlcpy(sb->fsname, g_path_get_basename(storage->uri), MAX_FILE_NAME_LEN);
	ctrl->start_segno = from_segno;	
	//TODO :config it
	//ctrl->is_compressed = TRUE;
	//HLOG_DEBUG("leave func %s", __func__);
	return ret;
}
#endif

/*
 * init_ffssim - initialize the FFSSIM
 * @param uri fs localtion
 * @return Return a handle to the FFSSIM
 */
struct ffssim_ctrl *init_ffssim(const char *uri)
{
	if(uri == NULL) {
		HLOG_ERROR("Params Error");
		return NULL;  
	}
	int ret = 0;
	struct ffssim_ctrl *ctrl = g_malloc0(sizeof(struct ffssim_ctrl));
	if (NULL == ctrl) {
		HLOG_ERROR("ctrl allocate error!");
		return NULL;
	}
	struct back_storage *storage = init_storage_handler(uri);
	if (storage == NULL) {
		HLOG_ERROR("[uri:%s] can not accessable", uri);
		ret = -1;
		goto out;
	}
	ctrl->storage = storage;
        //   amend 
	if (0 != init_from_superblock(ctrl->storage, ctrl)) {
		HLOG_ERROR("[uri:%s] read superblock failed", uri);
		ret = -1;
		goto out;
	}
        
	uint32_t segno = 0;
	uint32_t offset = 0;
	if (ctrl->last_segno != 0 || ctrl->last_offset != 0) {
		HLOG_DEBUG("Open from self segno!!");
		/*TODO*/
	}
	HLOG_INFO("Raw FFSSIM Ctrl Init Over ! uri:%s, max_fs_size:%llu, \
			chunk_size:%u, block_size:%u, last_segno:%u, last_offset:%u, \
			start_segno:%d",
			uri,
			ctrl->sb.max_fs_size,
			ctrl->sb.chunk_size,
			ctrl->sb.block_size,
			ctrl->last_segno,
			ctrl->last_offset,
			ctrl->start_segno); 
out:
	if (ret != 0) {
		fprintf(stderr, "Init FFSSIM Error\n");
		/*TODO: Free jobs*/
		return NULL;
	}
	return ctrl;
} 
